// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-11-19

package file_plugin

import (
	"errors"
	"fmt"
	"gitee.com/go-libs/log/common"
	"gitee.com/go-libs/log/conf"
	"os"
	"strings"
	"time"
)

// 输出日志.
type writer struct{}

// +------------------------------------------------------------------------------+
// | Interface methods                                                            |
// +------------------------------------------------------------------------------+

func (o *writer) Write(formatter common.LoggingFormatter, items []common.Item) (err error) {
	var (
		cfg    = conf.New()
		mapper = make(map[string][]string)
		times  = make(map[string]time.Time)
	)

	// 1. 遍历日志.
	for _, item := range items {
		// 2. 时间归类.
		//    默认模式下同一天的日志放在同一个文件中(如: 2024-09-10.log).
		key := item.Time().Format(cfg.FileAdapter.FileName)

		// 3. 初始化归类.
		if _, ok := mapper[key]; !ok {
			mapper[key] = make([]string, 0)
			times[key] = item.Time()
		}

		// 4. 加入列表.
		mapper[key] = append(mapper[key], formatter.ToString(item))
	}

	// 4. 写入数据.
	for name, lines := range mapper {
		if err = o.write(times[name], name, lines); err != nil {
			break
		}
	}
	return
}

// +------------------------------------------------------------------------------+
// | Access methods                                                               |
// +------------------------------------------------------------------------------+

func (o *writer) init() *writer { return o }

func (o *writer) write(tm time.Time, name string, list []string) (err error) {
	var (
		cfg  = conf.New()
		file *os.File
		info os.FileInfo
		path = fmt.Sprintf(`%s/%s`, cfg.FileAdapter.FilePath, tm.Format(cfg.FileAdapter.FileSeparator))
	)

	// 1. 检查目录.
	if info, err = os.Stat(path); err != nil {
		// 1.1 创建目录.
		if errors.Is(err, os.ErrNotExist) {
			err = os.MkdirAll(path, os.ModePerm)
		}
	} else {
		// 1.2 非法目录.
		if !info.IsDir() {
			err = fmt.Errorf(`invalid directory: %s`, path)
		}
	}

	// 2. 打开文件.
	if file, err = os.OpenFile(fmt.Sprintf(`%s/%s`, path, name), os.O_WRONLY|os.O_CREATE|os.O_APPEND, os.ModePerm); err != nil {
		return
	}

	// 2.1 关闭文件.
	defer func() {
		_ = file.Close()
	}()

	// 3. 写处内容.
	_, err = file.WriteString(strings.Join(list, "\n") + "\n")
	return
}
